﻿namespace NTLib.Core.Tasks
{
    using Log;
    using Memory;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Threading;

    /// <summary>
    /// Define an object that contains a CancellationTokenSource
    /// </summary>
    [DataContract]
    [NotThreadSafe]

    public abstract class CancellableObject : Disposable
    {
        #region Fields

        private readonly List<CancellationTokenSource> _sources;
        private CancellationToken _token;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="CancellableObject"/> class.
        /// </summary>
        public CancellableObject()
        {
            this._sources = new List<CancellationTokenSource>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the cancel token.
        /// </summary>
        [IgnoreDataMember]
        protected CancellationToken CancelToken
        {
            get
            {
                LazyInitializer();
                return this._token;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Lazies the initializer.
        /// </summary>
        private void LazyInitializer()
        {
            if (!this._sources.Any())
                this._sources.Add(new CancellationTokenSource());

            if (this._token == default(CancellationToken))
                this._token = this._sources.Last().Token;
        }

        /// <summary>
        /// Synchronizes the token.
        /// If the source pass in argument trigger the current will too
        /// </summary>
        /// <param name="triggerTokens">trigger tokens to synchronize.</param>
        public void SyncTokens(params CancellationToken[] triggerTokens)
        {
            LazyInitializer();
            List<CancellationToken> tokens = new List<CancellationToken>(triggerTokens);
            tokens.Add(this._token);
            var tmpsource = CancellationTokenSource.CreateLinkedTokenSource(tokens.ToArray());
            this._sources.Add(tmpsource);
            this._token = tmpsource.Token;
        }

        /// <summary>
        /// Dispose methods called whenever is the dipose origin.
        /// </summary>
        protected override void DisposeEveryTime()
        {
            if (this._sources.Any())
            {
                var tmps = this._sources.ToArray();
                this._sources.Clear();
                foreach (var s in _sources)
                {
                    try
                    {
                        s.Dispose();
                    }
                    catch (OperationCanceledException)
                    {

                    }
                    catch (Exception ex)
                    {
                        NTLog.Instance.RecordError(ex, this.GetType().Name);
                    }
                }
            }
            base.DisposeEveryTime();
        }

        #endregion
    }
}
